from flask import Blueprint, request, jsonify  # 导入Blueprint
import requests
import datetime
import json  # 用于处理coupon_json的序列化/反序列化
from mysql_utils import query_one, execute_sql, get_video_id_by_url  # 导入MySQL工具函数
import uuid  # 生成订单号
from wechatpayv3 import WeChatPay, WeChatPayType  # 导入微信支付工具
import traceback


# 创建支付相关蓝图
pay_bp = Blueprint('pay', __name__)
# 微信小程序配置
WX_CONFIG = {
    "appid": "wx001b6f4e30d935d0",
    "secret": "21e486562dfc30374d85b0995345d716"
}
# 微信支付配置（替换为你的实际参数）
PAY_CONFIG = {
    "mchid": "1650401853",  # 微信支付商户号
    "serial_no": "116CCF9243DF13383391CFA2725A85B2EBF07418",  # 商户API证书序列号
    "private_key": "E:\\apiclient_key.pem",  # 商户私钥路径
    # "certificate": "./apiclient_cert.pem",  # 商户证书路径
    "appid": WX_CONFIG["appid"],  # 小程序appid
    "notify_url": "https://1mp14468063ha.vicp.fun/api/payment/notify",  # 支付结果通知地址（需HTTPS）
    "apiv3_key":"OJGp7dShEuDcdwpZNx1ucLkzHlg73jtx"
}
# 初始化微信支付客户端
wechat_pay = WeChatPay(
    wechatpay_type=WeChatPayType.MINIPROG,
    mchid=PAY_CONFIG["mchid"],
    private_key=open(PAY_CONFIG["private_key"]).read(),
    # certificate=open(PAY_CONFIG["certificate"]).read(),
    cert_serial_no=PAY_CONFIG["serial_no"],
    appid=PAY_CONFIG["appid"],
    notify_url=PAY_CONFIG["notify_url"],
    apiv3_key=PAY_CONFIG["apiv3_key"]
)

# 新增：创建支付订单接口
@pay_bp.route('/createOrder', methods=['POST'])
def create_payment_order():
    data = request.get_json()
    user_id = data.get('user_id')
    amount = data.get('amount')
    download_type = data.get('download_type')
    video_url = data.get('video_url')

    if not all([user_id, amount, download_type, video_url]):
        return jsonify({"success": False, "message": "参数不全"})
        # 2. 查询video_id（关键：将URL转为整数ID）
    video_id = get_video_id_by_url(video_url)
    if not video_id:
        return jsonify({"success": False, "message": "视频不存在，请检查video_url"})

    try:
        # 3. 生成唯一订单号与创建时间
        order_no = f"order_{uuid.uuid4().hex[:16]}_{datetime.datetime.now().strftime('%Y%m%d')}"
        create_time = datetime.datetime.now().strftime('%Y-%m-%d %H:%M:%S')

        # 4. 插入orders表（此时video_id是整数，匹配数据库类型）
        insert_sql = """
           INSERT INTO orders 
           (order_no, video_id, coupon_id, original_price, actual_price, payment_status, create_time)
           VALUES (%s, %s, %s, %s, %s, %s, %s)
           """
        execute_sql(insert_sql, (order_no, video_id, None, amount, amount, 0, create_time))

        # 3. 调用微信支付API生成预支付单
        result = wechat_pay.pay(
            description="无水印视频下载",
            out_trade_no=order_no,
            amount={"total": round(amount * 100)},
            payer={"openid": user_id}
        )

        print("微信支付API返回:", result)

        # 处理返回结果
        if isinstance(result, tuple):
            status_code = result[0]
            response_body = result[1]
            if status_code == 200:
                response_data = json.loads(response_body)
                prepay_id = response_data.get('prepay_id')
            else:
                return jsonify({"success": False, "message": f"微信支付API返回错误，状态码: {status_code}"})
        else:
            prepay_id = result.get('prepay_id')

        if not prepay_id:
            return jsonify({"success": False, "message": "获取prepay_id失败"})

        # 4. 生成前端调起支付的参数
        timestamp = str(int(datetime.datetime.now().timestamp()))
        nonce_str = str(uuid.uuid4()).replace('-', '')[:32]
        package_str = f"prepay_id={prepay_id}"

        pay_params = {
            "appId": PAY_CONFIG['appid'],
            "timeStamp": timestamp,
            "nonceStr": nonce_str,
            "package": package_str,
            "signType": "RSA"
        }

        # 5. 计算签名 - 仅用cryptography库实现（无rsa依赖）
        try:
            # 步骤1：构造并修复签名字符串格式
            sign_str = f"{PAY_CONFIG['appid']}\n{timestamp}\n{nonce_str}\n{package_str}\n"
            sign_str = sign_str.replace('\r\n', '\n').strip('\r')  # 清除Windows换行符
            if not sign_str.endswith('\n'):
                sign_str += '\n'  # 确保最后有换行符
            print(f"最终签名字符串（repr）: {repr(sign_str)}")

            # 步骤2：将字符串编码为UTF-8字节流（关键）
            sign_bytes = sign_str.encode('utf-8')
            print(f"UTF-8编码后（hex）: {sign_bytes.hex()}")

            # 步骤3：加载商户私钥（确保路径正确，PKCS#8格式）
            from cryptography.hazmat.primitives import serialization
            from cryptography.hazmat.primitives.asymmetric import padding
            from cryptography.hazmat.primitives import hashes
            import base64
            import traceback

            # 读取私钥文件（替换为你的私钥路径，如PAY_CONFIG["private_key_path"]）
            private_key_path = "E:\\apiclient_key.pem"  # 确保此路径正确
            try:
                with open(private_key_path, "rb") as key_file:
                    private_key = serialization.load_pem_private_key(
                        key_file.read(),
                        password=None,  # 微信商户私钥默认无密码
                        backend=None
                    )
                print("私钥加载成功")
            except Exception as e:
                print(f"私钥加载失败: {str(e)}")
                print(f"私钥路径: {private_key_path}")
                traceback.print_exc()
                return jsonify({"success": False, "message": "私钥加载失败，请检查路径和格式"})

            # 步骤4：执行SHA256withRSA签名（微信v3标准算法）
            try:
                signature = private_key.sign(
                    sign_bytes,  # 使用UTF-8编码的字节流
                    padding.PKCS1v15(),  # 必须用PKCS#1 v1.5填充
                    hashes.SHA256()  # 必须用SHA256哈希算法
                )
            except Exception as e:
                print(f"签名算法执行失败: {str(e)}")
                traceback.print_exc()
                return jsonify({"success": False, "message": "签名算法执行失败"})

            # 步骤5：对签名结果进行Base64编码（得到最终paySign）
            pay_sign = base64.b64encode(signature).decode('utf-8')
            pay_params["paySign"] = pay_sign

            print(f"手动生成的paySign: {pay_sign}")
            print(f"paySign长度: {len(pay_sign)}")  # 正常约450字符左右

        except Exception as sign_error:
            print(f"签名失败: {str(sign_error)}")
            traceback.print_exc()
            return jsonify({"success": False, "message": f"签名失败：{str(sign_error)}"})

        # 6. 返回结果
        return jsonify({
            "success": True,
            "data": {
                "order_id": order_no,
                "pay_params": pay_params,
                "debug": {  # 添加调试信息到响应
                    "sign_str": sign_str,
                    "sign_str_hex": sign_str.encode().hex()
                }
            }
        })

    except Exception as e:
        print(f"创建订单异常: {str(e)}")
        import traceback
        traceback.print_exc()
        return jsonify({"success": False, "message": f"创建订单失败：{str(e)}"})
# 新增：支付结果通知接口（微信异步回调）- 修复400错误版
@pay_bp.route('/notify', methods=['POST'])
def payment_notify():
    # 1. 关键：获取微信回调的所有必要头信息（缺一不可）
    try:
        # 微信回调必传的4个Header参数
        signature = request.headers.get('Wechatpay-Signature')  # 签名
        timestamp = request.headers.get('Wechatpay-Timestamp')  # 时间戳
        nonce = request.headers.get('Wechatpay-Nonce')          # 随机串
        serial_no = request.headers.get('Wechatpay-Serial')     # 平台证书序列号（之前缺失！）
        body = request.data  # 原始请求体（不可用request.get_json()，会篡改数据）

        # 校验Header参数是否完整
        if not all([signature, timestamp, nonce, serial_no, body]):
            missing_params = []
            if not signature: missing_params.append('Wechatpay-Signature')
            if not timestamp: missing_params.append('Wechatpay-Timestamp')
            if not nonce: missing_params.append('Wechatpay-Nonce')
            if not serial_no: missing_params.append('Wechatpay-Serial')
            if not body: missing_params.append('请求体body')
            err_msg = f"回调参数缺失：{','.join(missing_params)}"
            print(f"回调失败：{err_msg}")
            # 返回400，但明确告知参数缺失（微信会重试）
            return jsonify({"code": "FAIL", "message": err_msg}), 400

        # 2. 验证微信通知的签名（核心步骤，依赖平台证书）
        try:
            # 调用wechatpay.verify_notify，传入平台证书序列号serial_no
            wechat_pay.verify_notify(
                signature=signature,
                timestamp=timestamp,
                nonce=nonce,
                body=body,
                cert_serial_no=serial_no  # 关键：补充平台证书序列号
            )
            print("签名验证成功")
        except Exception as sign_err:
            # 签名验证失败（常见原因：平台证书错误、参数篡改、时间戳过期）
            err_msg = f"签名验证失败：{str(sign_err)}"
            print(f"回调失败：{err_msg}")
            print(f"调试信息：signature={signature}, timestamp={timestamp}, nonce={nonce}, serial_no={serial_no}")
            return jsonify({"code": "FAIL", "message": err_msg}), 400

        # 3. 解析回调数据（验证通过后再解析）
        try:
            notify_data = json.loads(body.decode('utf-8'))  # 先解码再转JSON
        except json.JSONDecodeError as json_err:
            err_msg = f"回调数据格式错误（非JSON）：{str(json_err)}"
            print(f"回调失败：{err_msg}")
            return jsonify({"code": "FAIL", "message": err_msg}), 400

        # 4. 提取订单信息（确保字段存在，避免KeyError）
        out_trade_no = notify_data.get("out_trade_no")  # 商户订单号（你生成的order_id）
        trade_state = notify_data.get("trade_state")    # 支付状态（SUCCESS/FAIL等）
        if not out_trade_no or not trade_state:
            err_msg = f"回调数据缺失关键字段：out_trade_no={out_trade_no}, trade_state={trade_state}"
            print(f"回调失败：{err_msg}")
            return jsonify({"code": "FAIL", "message": err_msg}), 400

            # 5. 更新`orders`表的支付状态
        try:
            if trade_state == "SUCCESS":
                # 支付成功：更新payment_status为1，记录pay_time
                pay_time = datetime.datetime.now().strftime('%Y-%m-%d %H:%M:%S')
                update_sql = """
                   UPDATE orders 
                   SET payment_status = 1, pay_time = %s 
                   WHERE order_no = %s
                   """
                execute_sql(update_sql, (pay_time, out_trade_no))
            else:
                # 支付失败/关闭：更新payment_status为2
                update_sql = "UPDATE orders SET payment_status = 2 WHERE order_no = %s"
                execute_sql(update_sql, (out_trade_no,))

            print(f"订单{out_trade_no}支付状态：{trade_state}，已更新数据库")
        except Exception as db_err:
            # 数据库错误：返回400，微信会重试（避免订单状态不一致）
            err_msg = f"数据库更新失败：{str(db_err)}"
            print(f"回调失败：{err_msg}")
            traceback.print_exc()
            return jsonify({"code": "FAIL", "message": err_msg}), 400

        # 6. 关键：返回200状态码+SUCCESS响应（微信收到后停止重试）
        # 必须设置Content-Type为application/json（否则微信可能识别失败）
        response = jsonify({"code": "SUCCESS", "message": "回调处理成功"})
        response.headers['Content-Type'] = 'application/json'
        return response

    # 7. 全局异常捕获（避免接口崩溃）
    except Exception as global_err:
        err_msg = f"回调全局异常：{str(global_err)}"
        print(f"回调失败：{err_msg}")
        traceback.print_exc()
        response = jsonify({"code": "FAIL", "message": err_msg})
        response.headers['Content-Type'] = 'application/json'
        return response, 400


